﻿using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Odyssey.Consul.Implementations
{
    using Features;
    using Http;
    using Models;

    public class Agent : BaseConsulAPI, IAgent
    {
        public Agent(IHttpRequester httpRequester, IConsulConfiguration consulConfiguration) : base(httpRequester, consulConfiguration, EnumResource.Agent)
        {

        }

        private string BuildAgentPath(string action)
        {
            return BuildUri("agent", action);
        }

        public async Task<List<ResultMember>> ListMembers(QueryParameter queryParameter)
        {
            return await ApiSend<List<ResultMember>>(BuildAgentPath("members"), queryParameter: queryParameter, requestHeaders: BuildTokenHeader(EnumResource.Node));
        }

        public async Task<ResultConsulConfiguration> Self()
        {
            return await ApiSend<ResultConsulConfiguration>(BuildAgentPath("self"), requestHeaders: BuildTokenHeader());
        }

        public async Task Reload()
        {
            await ApiSendResponse(BuildAgentPath("reload"), enumConsulHttpMethod: EnumConsulHttpMethod.Put, requestHeaders: BuildTokenHeader());
        }


        public async Task EnableMaintenanceMode(ArguEnableMaintenanceMode arguEnableMaintenanceMode)
        {
            QueryParameter queryParameter = null;
            if (arguEnableMaintenanceMode != null)
            {
                queryParameter = new QueryParameter();
                if (arguEnableMaintenanceMode.Enable.HasValue)
                {
                    queryParameter.OtherParameters.Add("enable", arguEnableMaintenanceMode.Enable.ToString());
                }
                if (!string.IsNullOrWhiteSpace(arguEnableMaintenanceMode.Reason))
                {
                    queryParameter.OtherParameters.Add("reason", arguEnableMaintenanceMode.Reason);
                }
            }
            await ApiSendResponse(BuildAgentPath("maintenance"), null, EnumConsulHttpMethod.Put, queryParameter, BuildTokenHeader(EnumResource.Node));
        }

        public async Task<string> Metrics()
        {
            return await ApiSendString(BuildAgentPath("metrics"), EnumConsulHttpMethod.Get, requestHeaders: BuildTokenHeader());
        }

        #region Check

        private string BuildAgentCheckPath(string action)
        {
            return BuildUri("agent/check", action);
        }
        public async Task<List<ResultCheck>> CheckList()
        {
            var result = await ApiSend<Dictionary<string, ResultCheck>>(BuildAgentPath("checks"), requestHeaders: BuildTokenHeader(new EnumResource[] {
                EnumResource.Node,
                EnumResource.Service
            }));
            return result.Select(x => x.Value).ToList();
        }

        public async Task CheckRegister(ArguCheckRegister arguCheckRegister)
        {
            await ApiSendResponse(BuildAgentCheckPath("register"), arguCheckRegister, EnumConsulHttpMethod.Put, requestHeaders: BuildTokenHeader(new EnumResource[] {
                EnumResource.Node,
                EnumResource.Service
            }));
        }

        public async Task CheckDeregister(string id)
        {
            var path = BuildAgentCheckPath($"deregister/{id}");
            await ApiSendResponse(path, enumConsulHttpMethod: EnumConsulHttpMethod.Put, requestHeaders: BuildTokenHeader(new EnumResource[] {
                EnumResource.Node,
                EnumResource.Service
            }));
        }

        public async Task CheckTTLPass(ArguCheckTTL arguCheckTTL)
        {
            var path = BuildAgentCheckPath($"pass/{arguCheckTTL.ID}");
            await ApiSendResponse(path, new { arguCheckTTL.Note }, enumConsulHttpMethod: EnumConsulHttpMethod.Put, requestHeaders: BuildTokenHeader(new EnumResource[] {
                EnumResource.Node,
                EnumResource.Service
            }));
        }

        public async Task CheckTTLWarn(ArguCheckTTL arguCheckTTL)
        {
            var path = BuildAgentCheckPath($"warn/{arguCheckTTL.ID}");
            await ApiSendResponse(path, new { arguCheckTTL.Note }, enumConsulHttpMethod: EnumConsulHttpMethod.Put, requestHeaders: BuildTokenHeader(new EnumResource[] {
                EnumResource.Node,
                EnumResource.Service
            }));
        }

        public async Task CheckTTLFail(ArguCheckTTL arguCheckTTL)
        {
            var path = BuildAgentCheckPath($"fail/{arguCheckTTL.ID}");
            await ApiSendResponse(path, new { arguCheckTTL.Note }, enumConsulHttpMethod: EnumConsulHttpMethod.Put, requestHeaders: BuildTokenHeader(new EnumResource[] {
                EnumResource.Node,
                EnumResource.Service
            }));
        }

        public async Task CheckTTLUpdate(ArguCheckTTLUpdate arguCheckTTLUpdate)
        {
            var path = BuildAgentCheckPath($"fail/{arguCheckTTLUpdate.ID}");
            await ApiSendResponse(path,
                new
                {
                    arguCheckTTLUpdate.Status,
                    arguCheckTTLUpdate.Output
                },
                enumConsulHttpMethod: EnumConsulHttpMethod.Put,
                requestHeaders: BuildTokenHeader(new EnumResource[] {
                EnumResource.Node,
                EnumResource.Service
            }));
        }
        #endregion

        #region Service
        private string BuildAgenServicePath(string action)
        {
            return BuildUri("agent/service", action);
        }
        public async Task<List<ResultService>> ServiceList()
        {
            var result = await ApiSend<Dictionary<string, ResultService>>(BuildAgentPath("services"), requestHeaders: BuildTokenHeader(EnumResource.Service));
            return result.Select(x => x.Value).ToList();
        }

        public async Task<ResultService> ServiceConfiguration(string id)
        {
            var path = BuildAgenServicePath(id);
            return await ApiSend<ResultService>(path, requestHeaders: BuildTokenHeader(EnumResource.Service));
        }

        public async Task<List<ResultServiceHealth>> ServiceHealth(string id = "", string name = "")
        {
            var path = string.Empty;
            if (!string.IsNullOrWhiteSpace(name))
            {
                path = BuildAgentPath("health/service/name/" + name);
                return await ApiSend<List<ResultServiceHealth>>(path, requestHeaders: BuildTokenHeader(EnumResource.Service));
            }
            else
            {
                path = BuildAgentPath("health/service/id/" + id);
                var resultServiceHealth = await ApiSend<ResultServiceHealth>(path, requestHeaders: BuildTokenHeader(EnumResource.Service));
                var list = new List<ResultServiceHealth>();
                list.Add(resultServiceHealth);
                return list;
            }

        }

        public async Task ServiceRegister(ArguServiceRegister arguServiceRegister)
        {
            await ApiSendResponse(BuildAgenServicePath("register"),
                arguServiceRegister,
                EnumConsulHttpMethod.Put,
                requestHeaders: BuildTokenHeader(EnumResource.Service));
        }

        public async Task ServiceDeregister(string id)
        {
            var path = BuildAgenServicePath($"deregister/{id}");
            await ApiSendResponse(path,
              enumConsulHttpMethod: EnumConsulHttpMethod.Put,
              requestHeaders: BuildTokenHeader(EnumResource.Service));
        }

        public async Task ServiceEnableMaintenance(ArguServiceEnableMaintenance arguServiceEnableMaintenance)
        {
            var path = BuildAgenServicePath($"maintenance/{arguServiceEnableMaintenance.ServiceID}");
            QueryParameter queryParameter = null;

            if (arguServiceEnableMaintenance != null)
            {
                queryParameter = new QueryParameter();
                if (arguServiceEnableMaintenance.Enable.HasValue)
                {
                    queryParameter.OtherParameters.Add("enable", arguServiceEnableMaintenance.Enable.ToString());
                }
                if (!string.IsNullOrWhiteSpace(arguServiceEnableMaintenance.Reason))
                {
                    queryParameter.OtherParameters.Add("reason", arguServiceEnableMaintenance.Reason);
                }
            }
            await ApiSendResponse(path, null, EnumConsulHttpMethod.Put, queryParameter, BuildTokenHeader(EnumResource.Service));
        }
        #endregion

        #region Connect
        private string BuildAgenConnectPath(string action)
        {
            return BuildUri("agent/connect", action);
        }
        public async Task<ResultAuthorized> Authorize(ArguAuthorize arguAuthorize)
        {
            return await ApiSend<ArguAuthorize, ResultAuthorized>(BuildAgenConnectPath("authorize"), arguAuthorize, EnumConsulHttpMethod.Post, requestHeaders: BuildTokenHeader(EnumResource.Service));
        }

        public async Task<ResultCARoots> CARoots()
        {
            return await ApiSend<ResultCARoots>(BuildAgenConnectPath("ca/roots"));
        }

        public async Task<ResultServiceLeafCertificate> ServiceLeafCertificate(string serviceName)
        {
            var path = BuildAgenConnectPath($"ca/leaf/{serviceName}");
            return await ApiSend<ResultServiceLeafCertificate>(path);
        }

        #endregion
    }
}
